#!/usr/bin/python
#coding: utf-8

"""
运行环境：Python2.7.12 + Pycharm
Game： 2048
当鼠标点击
W   上
S   下
A   左
D   右
当点击其它键的时候，抛出异常，不对异常进行处理

对于输出字体的颜色的处理：http://blog.csdn.net/wuxiushu/article/details/52427374

输出：最终的得分，即为每次相加的和

可修改：对于上下左右移动的时候，可以使用其它方法进行计算每一行移动后的结果，感兴趣的可以尝试下
"""

import random

class Game_2048(object):
    def __init__(self):
        self.matix = [[0 for j in range(4)] for i in range(4)]   # 初始化一个 4 * 4 的游戏界面
        self.score = 0    # 初始化最终得分为0

    # 判断是否为0，如果为0的话就输出空，否则输出当前的数字
    def isZero(self, s):
        return str(s) if s != 0 else ""

    # 绘图函数
    def display(self):
        print(u"\r\
                ┌──┬──┬──┬──┐\n\
                │%4s│%4s│%4s│%4s│\n\
                ├──┬──┬──┬──┤\n\
                │%4s│%4s│%4s│%4s│\n\
                ├──┬──┬──┬──┤\n\
                │%4s│%4s│%4s│%4s│\n\
                ├──┬──┬──┬──┤\n\
                │%4s│%4s│%4s│%4s│\n\
                └──┴──┴──┴──┘" \
              % (self.isZero(self.matix[0][0]), self.isZero(self.matix[0][1]), self.isZero(self.matix[0][2]), self.isZero(self.matix[0][3]), \
                 self.isZero(self.matix[1][0]), self.isZero(self.matix[1][1]), self.isZero(self.matix[1][2]), self.isZero(self.matix[1][3]), \
                 self.isZero(self.matix[2][0]), self.isZero(self.matix[2][1]), self.isZero(self.matix[2][2]), self.isZero(self.matix[2][3]), \
                 self.isZero(self.matix[3][0]), self.isZero(self.matix[3][1]), self.isZero(self.matix[3][2]), self.isZero(self.matix[3][3]),)
              )

    # 初始化游戏
    def initGame(self):
        # 生成两个随机数
        self.addRandomNum(2)

    # 向右移动
    def moveRight(self):
        for i in range(4):  # 行
            for j in range(3, 0, -1):  # 列，从后往前遍历， 不能取到最左边位置，因为再往左已经没有可以移动的元素
                for k in range(j - 1, -1, -1):  # 列，对当前行 j 之前的元素进行判断
                    if self.matix[i][k] > 0:  # 为0的时候不需要判断
                        # 如果说 j 位置为 0 ，则直接放在该位置
                        # 此时并不能结束最内层循环，比如下面这个例子(一行数据)：4 4 0 0，往右移动的时候
                        # 执行这一步以后，结果为：4 0 0 4
                        # 如果终止的话此后并不会执行相加操作，最终结果会变为：0 0 4 4
                        # 而最终结果应该为：0 0 0 8
                        if self.matix[i][j] == 0:
                            self.matix[i][j], self.matix[i][k] = self.matix[i][k], 0
                        elif self.matix[i][j] == self.matix[i][k]:  # 相等的话，则相加
                            self.score += self.matix[i][k] * 2
                            self.matix[i][j], self.matix[i][k] = self.matix[i][k] * 2, 0
                            # 当 self.matix[i][j] ==  self.matix[i][k] 时，最内层 for 循环执行完一次以后就要终止，因为不终止的话可能会执行多次相加操作
                            # 例如：8 4 4 0， 如果不终止，则执行过程中应该为
                            # 8 4 0 4
                            # 8 0 0 8
                            # 0 0 0 16
                            # 结果出现错误，这应该是执行两次右移的结果
                            # 终止的话，最终结果应该为 0 0 8 8
                            break
        # 再生成一个随机数
        self.addRandomNum(1)

    # 以下三个移动方向处理方法相同，不再赘余

    # 向左移动
    def moveLeft(self):
        for i in range(4):
            for j in range(3):
                for k in range(j + 1, 4):
                    if self.matix[i][k] > 0:
                        if self.matix[i][j] == 0:
                            self.matix[i][j], self.matix[i][k] = self.matix[i][k], 0
                        elif self.matix[i][k] == self.matix[i][j]:
                            self.score += self.matix[i][k] * 2
                            self.matix[i][j], self.matix[i][k] = self.matix[i][k] * 2, 0
                            break
        self.addRandomNum(1)

    # 向上移动
    def moveUp(self):
        for i in range(4):  # 列
            for j in range(3):  # 行
                for k in range(j + 1, 4):   # 行
                    if self.matix[k][i] > 0:
                        if self.matix[j][i] == 0:
                            self.matix[j][i], self.matix[k][i] = self.matix[k][i], 0
                        elif self.matix[j][i] == self.matix[k][i]:
                            self.score += self.matix[k][i] * 2
                            self.matix[j][i], self.matix[k][i] = self.matix[k][i] * 2, 0
                            break
        self.addRandomNum(1)

    # 向下移动
    def moveDown(self):
        for i in range(4):
            for j in range(3, 0, -1):
                for k in range(j - 1, -1, -1):
                    if self.matix[k][i] > 0:
                        if self.matix[j][i] == 0:
                            self.matix[j][i], self.matix[k][i] = self.matix[k][i], 0
                        elif self.matix[j][i] == self.matix[k][i]:
                            self.score += self.matix[k][i] * 2
                            self.matix[j][i], self.matix[k][i] = self.matix[k][i] * 2, 0
                            break
        self.addRandomNum(1)

    # 每次处理完移动以后都添加一个新的随机数
    def addRandomNum(self, num):
        while True:
            # 随机生成数字 2 或 4，2是大概率事件
            k = 2 if random.randrange(0, 10) > 1 else 4
            # 随机生成矩阵初始化下标
            s = divmod(random.randrange(0, 16), 4)

            # 只能对值为 0 的位置进行赋值
            if self.matix[s[0]][s[1]] == 0:
                self.matix[s[0]][s[1]] = k
                num -= 1

            # 每次只能初始化两个位置
            if num <= 0:
                break
        self.display()

    # 检查16个位置是否都已经填充
    def check(self):
        for x in self.matix:
            if x.count(0) > 0:
                return False
        return True

    def start(self):
        flag = True
        print u"\t\t\033[31;5m Welcome to play the game of 2048 \033[31;5m"
        self.initGame()
        while flag == True:
            try:
                print(u'\t\t\033[33;1m You Score:%s\033[0m' % (self.score))
                st = raw_input(u'\033[33;1m (↑:w) (↓:s) (←:a) (→:d),q(quit) :\033[0m')
                if st == 'a':
                    self.moveLeft()
                elif st == 'd':
                    self.moveRight()
                elif st == 's':
                    self.moveDown()
                elif st == 'w':
                    self.moveUp()
                elif st == "q":
                    print(u'\n\n\t\033[33;1m The Final Score is :%s\033[0m' % (self.score))
                    flag = False
                    continue
                if self.check() == True:
                    print(u'\n\n\t\033[33;1m The Final Score is :%s\033[0m' % (self.score))
                    flag = False
            except Exception as e:
                # 输入异常，不做处理
                pass

if __name__ == "__main__":
    game = Game_2048()
    # 测试数据
    # game.display()
    # game.initGame()
    # game.moveRight()
    # game.moveLeft()
    # game.moveUp()
    # game.moveDown()
    game.start()